package com.scau402.system1.service.impl;

import com.github.pagehelper.PageInfo;
import com.scau402.common.constant.JadeConstants;
import com.scau402.common.core.domain.AjaxResult;
import com.scau402.common.core.domain.entity.SysUser;
import com.scau402.common.core.page.TableDataInfo;
import com.scau402.common.exception.ServiceException;
import com.scau402.common.utils.DataUtils;
import com.scau402.common.utils.PageUtils;
import com.scau402.common.utils.SecurityUtils;
import com.scau402.system.service.IWmsJadeService;
import com.scau402.system1.domain.dto.AuditOrderDTO;
import com.scau402.system1.domain.dto.WmsAuditOrderDTO;
import com.scau402.system1.domain.po.*;
import com.scau402.system1.domain.query.AuditOrderQuery;
import com.scau402.system1.domain.query.WmsAdjustBoundOrderQuery;
import com.scau402.system1.domain.vo.WmsInboundOrderAndDetailVO;
import com.scau402.system1.domain.vo.WmsOutboundOrderAndDetailVO;
import com.scau402.system1.repository.*;
import com.scau402.system1.service.IWmsAuditOrderService;
import com.scau402.system1.utils.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 审核模块Service实现类
 * @since 2024/2/5
 */
@Service
@Slf4j
@Transactional
public class IWmsAuditOrderServiceImpl implements IWmsAuditOrderService {
    @Autowired
    private IWmsAuditOrderRepository auditOrderRepo;
    @Autowired
    private IWmsJadeService jadeService;
    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private IWmsOutboundOrderRepository outboundOrderRepo;
    @Autowired
    private IWmsJadeRepository jadeRepo;
    @Autowired
    private WmsWarehouseStorageService warehouseStorageService;
    @Autowired
    private IWmsInboundOrderRepository inboundOrderRepo;
    @Autowired
    private IWmsAdjustOrderRepository adjustOrderRepo;

    /**
     * 根据审核类型获取审核单
     * @param type 审核类型：0：价格调整、1：出借天数、2：库存调整、3: 长期出借
     * @return 审核单列表
     * @since 2024/2/6
     * @deprecated 为不同的审核单进行了权限细分，将switch分割成了不同的 <pre>{@code list***AuditOrder()}</pre>方法，同时增加了分页功能
     * @see IWmsAuditOrderServiceImpl#listAdjustboundAuditOrder(WmsAdjustBoundOrderQuery)
     * @see IWmsAuditOrderServiceImpl#listOutboundAuditOrder()
     * @see IWmsAuditOrderServiceImpl#listPriceAdjustAuditOrder(WmsAdjustBoundOrderQuery)
     * @see IWmsAuditOrderServiceImpl#listInboundAuditOrder()
     */
    @Deprecated
    @Override
    public AjaxResult listAuditOrder(String type,WmsAdjustBoundOrderQuery adjustBoundOrderQuery) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        Long tenantId = user.getTenantId();
        adjustBoundOrderQuery.setTenantId(tenantId);
        switch (type){
            // 入库
            case "3":{
                List<WmsAuditOrderDTO<WmsInboundOrderAndDetailVO>> inboundOrderList = auditOrderRepo.findInBoundList(tenantId);
                return AjaxResult.success(inboundOrderList);
            }
            // 库存调整审核
            case "2":{
                List<WmsAuditOrderDTO<WmsAdjustBoundOrderDetailPO>> auditOrderList =  auditOrderRepo.findAdjustList(adjustBoundOrderQuery);
                return AjaxResult.success(auditOrderList);
            }
            // 长期出借审核
            case "1":{
                List<WmsAuditOrderDTO<WmsOutboundOrderAndDetailVO>> outboundOrderList =  auditOrderRepo.findOutBoundList(tenantId);
                return AjaxResult.success(outboundOrderList);
            }
            // 价格调整
            case "0":{

                return AjaxResult.success();
            }
        }
        return AjaxResult.error("审核类型错误!");
    }

    /**
     * 获取长期出借审核单
     * @return 审核单列表
     * @since 2024/2/15
     */
    @Override
    @PreAuthorize("@ss.hasPermi('system:audit:query:outbound')")
    public TableDataInfo listOutboundAuditOrder() {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        Long tenantId = user.getTenantId();
        //分页
        PageUtils.startPage();
        List<WmsAuditOrderDTO<WmsOutboundOrderAndDetailVO>> outboundOrderList =  auditOrderRepo.findOutBoundList(tenantId);
        //分页信息加入MDC
        PageUtils.fetchSessionPageInfo(new PageInfo<>(outboundOrderList));
        if(DataUtils.isEmpty(outboundOrderList)){
            return new TableDataInfo();
        }
        return PageUtils.getDataTableFromList(outboundOrderList);
    }

    /**
     * 获取库存调整审核单
     * @return 审核单列表
     * @since 2024/2/15
     */
    @Override
    public TableDataInfo listAdjustboundAuditOrder(WmsAdjustBoundOrderQuery auditOrderQuery) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        auditOrderQuery.setTenantId(user.getTenantId());
        //分页
        PageUtils.startPage();
        List<WmsAuditOrderDTO<WmsAdjustBoundOrderDetailPO>> auditOrderList =  auditOrderRepo.findAdjustList(auditOrderQuery);
        //分页信息加入MDC
        PageUtils.fetchSessionPageInfo(new PageInfo<>(auditOrderList));
        if(DataUtils.isEmpty(auditOrderList)){
            return new TableDataInfo();
        }
        return PageUtils.getDataTableFromList(auditOrderList);

    }

    /**
     * 获取价格调整审核单
     * @return 审核单列表
     * @since 2024/2/15
     */
    // TODO:待实现
    @Override
   public TableDataInfo listPriceAdjustAuditOrder(WmsAdjustBoundOrderQuery auditOrderQuery) {
////        SysUser user = SecurityUtils.getLoginUser().getUser();
////        auditOrderQuery.setTenantId(user.getTenantId());
////        //分页
////        PageUtils.startPage();
////        List<WmsAuditOrderDTO<WmsAdjustPriceOrderDetailPO>> auditOrderList =  auditOrderRepo.findAdjustList(auditOrderQuery);
////        //分页信息加入MDC
////        PageUtils.fetchSessionPageInfo(new PageInfo<>(auditOrderList));
////        if(DataUtils.isEmpty(auditOrderList)){
////            return new TableDataInfo();
////        }
////        return PageUtils.getDataTableFromList(auditOrderList);
        return null;
    }

    /**
     * 获取入库审核单列表
     * @return 审核单列表
     * @since 2024/2/19
     */
    @Override
    @PreAuthorize("@ss.hasPermi('system:audit:query:inbound')")
    public TableDataInfo listInboundAuditOrder() {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        Long tenantId = user.getTenantId();
        // 分页查询
        PageUtils.startPage();
        // 查询相关数据
        List<WmsAuditOrderDTO<WmsInboundOrderAndDetailVO>> auditOrderList = auditOrderRepo.findInBoundList(tenantId);
        PageUtils.fetchSessionPageInfo(new PageInfo<>(auditOrderList));
        if(DataUtils.isEmpty(auditOrderList)){
            return new TableDataInfo();
        }
        return PageUtils.getDataTableFromList(auditOrderList);
    }

    /**
     * 批量审核
     * @param auditOrderDTO 审核动作DTO
     * @return
     * @since 2024/2/5
     */
    @Override
    public AjaxResult audit(AuditOrderDTO auditOrderDTO) {
        // TODO: 参数校验

        // 根据审核单id查询其中未审核的审核单
        List<WmsAuditOrderPO> auditList = auditOrderRepo.findUnAuditList(auditOrderDTO.getIds());
        if (auditList.isEmpty()) {
            return AjaxResult.error("未找到对应审核单!");
        }

        //获取参数以及准备更新数据
        LocalDateTime now = LocalDateTime.now();
        String userName = SecurityUtils.getLoginUser().getUser().getUserName();
        String remark = auditOrderDTO.getRemark();

        //更新审核单数据
        auditList = auditList.stream().peek(auditOrder -> {
            auditOrder.setStatus(auditOrderDTO.getStatus());
            auditOrder.setAuditTime(now);
            auditOrder.setAuditedBy(userName);
            auditOrder.setRemark(remark);
        }).collect(Collectors.toList());

        // 如果审核结果是通过
        if(auditOrderDTO.getStatus().equals("1")){
            // TODO: 更新被审核的数据
            auditList.forEach(audit->{
                switch (audit.getType()) {
                    //价格调整
                    case "0":{break;}
                    //出借天数
                    case "1":{
                        updateOutboundAuditOrder(audit);
                        break;
                    }
                    //库存调整
                    case "2":{
                        updateAdjustBoundAuditOrder(audit);
                        break;
                    }
                    //入库
                    case "3":{
                        updateInboundAuditOrder(audit);
                        break;
                    }
                    default: {
                        log.warn("审核操作：未知审核类型：{}",audit.getType());
                        break;
                    }
                }
            });
        }

        //更新入库
        auditOrderRepo.update(auditList);

        return AjaxResult.success();
    }

    /**
     * 更新库存调整
     * @param audit 审核单PO
     * @since 2024/2/20
     */
    // TODO: 待实现 2024/2/23
    private void updateAdjustBoundAuditOrder(WmsAuditOrderPO audit) {
        if(1==1) return;
        // 获取绑定了审核单的库存调整单信息
        WmsAdjustBoundOrderDetailPO detailPO = adjustOrderRepo.findByAudit(audit);
        // 调整仓位容量数据
        warehouseStorageService.addInventory(detailPO.getStorageId(),detailPO.getNewNum() - detailPO.getOriNum());
        // 思路：库存调整单可能需要添加需要 删除/新增 的翡翠信息字段
        // TODO：调整翡翠信息
    }

    /**
     * 更新入库单信息
     * @param audit 审核单PO
     */
    private void updateInboundAuditOrder(WmsAuditOrderPO audit) {
        // 获取绑定了审核单的入库单列表
        WmsInboundOrderPO inbound = inboundOrderRepo.findInboundByAudit(audit);
        // 通过入库单获取详情单列表
        List<WmsInboundOrderDetailPO> detailPOList = inboundOrderRepo.findInboundDetailByOrderCode(inbound.getOrderCode());
        // 通过入库单类型和详情单列表修改翡翠状态
        switch (inbound.getOrderType()) {
            //采购入库
            case "0": {
                Map<Long,Long> map = new HashMap<>();
                for (int i = 0; i < detailPOList.size(); i++) {
                    jadeRepo.updateVisibleByJadeId(detailPOList.get(i).getJadeId(), JadeConstants.JADE_VISIBLE);
                    WmsJadePO po = jadeRepo.findQuantityByJadeId(detailPOList.get(i).getJadeId());
                    map.put(po.getStorageId(),map.getOrDefault(po.getStorageId(),0L)+po.getJadeQuantity());
                }
                // 调整仓位已使用容量
                map.forEach((storageId,quantity)->{
                    //仅使用最大容量和已使用容量
                    WmsWarehouseStoragePO DO = warehouseStorageService.selectCapById(storageId);
                    if(DO.getUsedCap()+quantity<=DO.getMaxCap()){
                        warehouseStorageService.addInventory(storageId,quantity);
                    }
                    else throw new ServiceException("仓位容量已超额，请退回重提，或重设仓位容量");
                });
                break;
            }
            //借货入库
            case "1":{
                Map<Long,Long> map = new HashMap<>();
                for (int i = 0; i < detailPOList.size(); i++) {
                    jadeRepo.updateVisibleByJadeId(detailPOList.get(i).getJadeId(), JadeConstants.JADE_VISIBLE);
                    WmsJadePO po = jadeRepo.findQuantityByJadeId(detailPOList.get(i).getJadeId());
                    map.put(po.getStorageId(),map.getOrDefault(po.getStorageId(),0L)+po.getJadeQuantity());
                }
                // 调整仓位已使用容量
                map.forEach((storageId,quantity)->{
                    //仅使用最大容量和已使用容量
                    WmsWarehouseStoragePO DO = warehouseStorageService.selectCapById(storageId);
                    if(DO.getUsedCap()+quantity<=DO.getMaxCap()){
                        warehouseStorageService.addInventory(storageId,quantity);
                    }
                    else throw new ServiceException("仓位容量已超额，请退回重提，或重设仓位容量");
                });
                break;
            }
            //还货入库
            case "2":{
                Map<Long,Long> map = new HashMap<>();
                for (int i = 0; i < detailPOList.size(); i++) {
                    jadeRepo.updateVisibleByJadeId(detailPOList.get(i).getJadeId(), JadeConstants.JADE_IN_WAREHOUSE);
                    WmsJadePO po = jadeRepo.findQuantityByJadeId(detailPOList.get(i).getJadeId());
                    map.put(po.getStorageId(),map.getOrDefault(po.getStorageId(),0L)+po.getJadeQuantity());
                }
                // 调整仓位已使用容量
                map.forEach((storageId,quantity)->{
                    //仅使用最大容量和已使用容量
                    WmsWarehouseStoragePO DO = warehouseStorageService.selectCapById(storageId);
                    if(DO.getUsedCap()+quantity<=DO.getMaxCap()){
                        warehouseStorageService.addInventory(storageId,quantity);
                    }
                    else throw new ServiceException("仓位容量已超额，请退回重提，或重设仓位容量");
                });
                break;
            }
            default: break;
        }
    }

    /**
     * 更新出借单信息
     * @param audit 审核单PO
     */
    private void updateOutboundAuditOrder(WmsAuditOrderPO audit){
        // 获取绑定审核单的出库单对应的详情单
        List<WmsOutboundOrderDetailDO> detailList = outboundOrderRepo.findOutboundDetailListByAuditId(audit.getId());
        if (detailList.isEmpty()) {
            log.warn("审核单id:{} , 详情单列表为空",audit.getId());
            return;
        }
        //获取详情单对应的翡翠信息
        List<WmsJadePO> jadeList = jadeRepo.findJadeByIds(
                //获取翡翠id列表
                detailList.stream().map(WmsOutboundOrderDetailDO::getJadeId).collect(Collectors.toList())
        );
        //列表为空
        if (jadeList.isEmpty()) {
            log.warn("审核单id:{} ,jadeList为空",audit.getId());
            return;
        }
        //更新翡翠信息
        jadeList.forEach(jade->{
            // 更新仓位已用容量信息
            warehouseStorageService.updateInventory(jade.getStorageId(),jade.getJadeQuantity());
            // 更新翡翠状态
            jadeService.updateJadeStatus("2",jade.getId());
        });
    }

    /**
     * 创建审核单
     * @param type 审核类型：0：价格调整、1：出借天数、2：库存调整
     * @param id 发起单id——如库存调整详情单id/出库单id/价格调整单id等
     * @return 审核单PO
     * @since 2024/2/5
     */
    @Override
    @Transactional
    public Long create(String type, Long id) {
        if(id<=0L) return null;
        SysUser user = SecurityUtils.getLoginUser().getUser();
        WmsAuditOrderPO po = new WmsAuditOrderPO(idGenerator,user,type,id);
        auditOrderRepo.save(po);
        return po.getId();
    }
}
